﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Erau.ERBParser
{
	public enum InstructionType
	{
		NULL,		// 0을 오류로 취급하기 위해 사용.
		VAR,		// 변수 생성
		SET,		// 변수에 값 대입
		CALL,		// 함수 호출
		RETURN,		// 함수의 리턴값 반환
		IF,			// IF 제어구문의 시작
		ELSE,
		ELSEIF,
		ENDIF,	
		FOR,		// FOR 반복 제어구문의 시작
		NEXT,		// FOR 구문의 끝.
		BREAK,		// IF나 FOR 제어구문을 빠져나감. 즉 ENDIF나 NEXT 위치로 이동.
		END
	}

	public abstract class InstructionLine
	{
		public InstructionType instruction;
		public ScriptFunction parentFunction;
		public InstructionLine NextLine;

		protected ScriptPosition pos;

		public void Execute()
		{
			// 실행
			ExecuteSingleLine();

			// 다음 라인 실행
			if (NextLine != null)
				NextLine.Execute();
		}

		abstract public void ExecuteSingleLine();
	}

	public class CallInstructionLine : InstructionLine
	{
		string functionName;
		public List<VariableToken> Args = new List<VariableToken>();

		public CallInstructionLine(StringBuffer line, ScriptFunction parentFunction, ScriptPosition pos)
		{
			instruction = InstructionType.CALL;
			this.parentFunction = parentFunction;
			this.pos = pos;

			// 첫번째 토큰은 함수호출 명령어인 CALL이어야 한다.
			if (line.GetToken(' ') != "CALL")
				throw new Exception("함수호출아님");

			// @다음 공백까지 이어지는 문자열은 호출할 함수의 이름. StringToken 타입.
			functionName = line.GetToken(' ');

			// 남은 문자열을 ','로 구분.
			string[] argStrs = line.GetTokens(',');

			// 구분된 각 문자열을 VariableToken으로 등록.
			foreach (string arg in argStrs)
				Args.Add(new VariableToken(arg));
		}

		override public void ExecuteSingleLine()
		{

		}
	}

	public class ReturnInstructionLine : InstructionLine
	{
		VariableToken returnValue;

		public ReturnInstructionLine(StringBuffer line, ScriptFunction parentFunction, ScriptPosition pos)
		{
			instruction = InstructionType.RETURN;
			this.parentFunction = parentFunction;
			this.pos = pos;

			// 첫번째 토큰은 RETURN이어야 한다.
			if (line.GetToken(' ') != "RETURN")
				throw new Exception("리턴명령아님");

			// 뒤에 붙을 수 있는 건 리턴할 변수뿐임.
			returnValue = new VariableToken(line);
		}

		override public void ExecuteSingleLine()
		{
			// 리턴할 수식의 실행결과를 함수의 리턴값 변수에 추가.
			parentFunction.returnValue = returnValue.Eval();
		}
	}

	public class SetInstructionLine : InstructionLine
	{
		public SetInstructionLine(StringBuffer line)
		{

		}

		override public void ExecuteSingleLine()
		{

		}
	}
}
